home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 February
/
EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso
/
earcd
/
comm2
/
xbtx.lha
/
Source
/
BTXDecode.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-03
|
16KB
|
670 lines
/*
** $Id: BTXDecode.cpp 1.1 1995/12/03 12:16:23 olsen Exp olsen $
**
** :ts=4
*/
/*
* Amiga changes copyright © 1995 by Olaf Barthel, All Rights Reserved
*
* Copyright (c) 1992, 1993 Arno Augustin, Frank Hoering, University of
* Erlangen-Nuremberg, Germany.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* Erlangen-Nuremberg, Germany.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software has not been validated by the ``Bundesamt fuer Zulassungen in
* der Telekommunikation'' of the ``Deutsche Bundepost Telekom'' and thus
* must not be used for accessing the BTX-Network of the Telekom in Germany.
*
* Diese Software hat keine Zulassung durch das Bundesamt fuer Zulassungen in
* der Telekommunikation der Deutschen Bundespost Telekom und darf daher nicht
* am Netz der Deutschen Bundespost Telekom in Deutschland betrieben werden.
*/
/****************************************************************************/
#include <string.h>
#include <stdlib.h>
/****************************************************************************/
#ifndef _BTXSERVICE_HPP
#include "BTXService.hpp"
#endif
/****************************************************************************/
#define FCS_32(crc,c) (crctab[((crc) ^ (c)) & 0xff] ^ ((crc) >> 8))
/****************************************************************************/
/**************************************************************
lzhuf.c
written by Haruyasu Yoshizaki 11/20/1988
some minor changes 4/6/1989
comments translated by Haruhiko Okumura 4/7/1989
modified for Btx-FIF by InfoTeSys GmhH 1991-11-04
: use malloc() instead of huge static areas
: files have to be opened outside of this module
: FCS-check inluded
:
: length field "long(Filesize)" has been removed from file
**************************************************************/
/********** LZSS compression **********/
#define N 4096 /* buffer size */
#define F 60 /* lookahead buffer size */
#define THRESHOLD 2
#define NIL N /* leaf of tree */
#define text_buf_len (N + F - 1)
#define N_CHAR (256 - THRESHOLD + F) /* kinds of characters (character code = 0..N_CHAR-1) */
#define T (N_CHAR * 2 - 1) /* size of table */
#define R (T - 1) /* position of root */
#define MAX_FREQ 0x8000 /* updates tree when the */
/* root frequency comes to this value. */
struct lzh_env
{
UBYTE InpBuf[2048];
WORD InpPos;
WORD InpMax;
UBYTE OutBuf[1024];
WORD OutPos;
WORD OutMax;
UWORD freq[T + 1]; /* frequency table */
WORD prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */
/* elements [T..T + N_CHAR - 1] which are used to get */
/* the positions of leaves corresponding to the codes. */
WORD son[T]; /* pointers to child nodes (son[], son[] + 1) */
ULONG crctab[256];
UBYTE *text_buf;
WORD match_position;
WORD match_length;
WORD *lson; /* [N + 1]; */
WORD *rson; /* [N + 257]; */
WORD *dad; /* [N + 1]; */
UWORD getbuf;
WORD getlen;
FILE *infile;
FILE *outfile;
};
STATIC WORD InpByt(struct lzh_env *LZHENV)
{
if(LZHENV->InpPos >= LZHENV->InpMax)
{
if((LZHENV->InpMax = (WORD)fread(LZHENV->InpBuf,1,LZHENV->InpMax,LZHENV->infile)) < 1)
return(0);
LZHENV->InpPos = 0;
}
return(LZHENV->InpBuf[LZHENV->InpPos++]);
}
STATIC WORD OutByt(struct lzh_env *LZHENV,WORD BY)
{
LZHENV->OutBuf[LZHENV->OutPos++] = (UBYTE)BY;
if(LZHENV->OutPos == LZHENV->OutMax)
{
if(fwrite(LZHENV->OutBuf,LZHENV->OutPos,1,LZHENV->outfile) < 1)
return(0);
LZHENV->OutPos = 0;
}
return(1);
}
STATIC WORD GetBit(struct lzh_env *LZHENV) /* get one bit */
{
WORD i,j;
j = LZHENV->getlen;
while(j <= 8)
{
if((i = InpByt(LZHENV)) == EOF)
i = 0;
LZHENV->getbuf |= (i << (8 - j));
j += 8;
}
i = (WORD)LZHENV->getbuf;
LZHENV->getbuf <<= 1;
LZHENV->getlen = --j;
return((WORD)(i < 0));
}
STATIC WORD GetByte(struct lzh_env *LZHENV) /* get one byte */
{
UWORD i;
WORD j;
j = LZHENV->getlen;
while(j <= 8)
{
if((i = InpByt(LZHENV)) == EOF)
i = 0;
LZHENV->getbuf |= i << (8 - j);
j += 8;
}
i = LZHENV->getbuf;
LZHENV->getbuf <<= 8;
LZHENV->getlen = (WORD)(j - 8);
return((WORD)((i >> 8) & 0xff));
}
STATIC VOID StopHuff(struct lzh_env *LZHENV)
{
if(LZHENV->lson)
free(LZHENV->lson);
if(LZHENV->rson)
free(LZHENV->rson);
if(LZHENV->dad)
free(LZHENV->dad);
if(LZHENV->text_buf)
free(LZHENV->text_buf);
free(LZHENV);
}
STATIC VOID initCRC(ULONG *crctab)
{
WORD i,j;
ULONG crc;
for(i = 0 ; i < 256 ; i++)
{
crc = i;
for(j = 0 ; j < 8 ; j++)
{
if(crc & 1)
crc = (crc >> 1) ^ 0xEDB88320;
else
crc >>= 1;
}
crctab[i] = crc;
}
}
/* initialization of tree */
STATIC struct lzh_env *StartHuff(VOID)
{
struct lzh_env *LZHENV;
WORD i,j;
if(!(LZHENV = (struct lzh_env *)malloc(sizeof(struct lzh_env))))
return(NULL);
memset(LZHENV,0,sizeof(struct lzh_env));
LZHENV->lson = (WORD *)malloc((N + 1) * sizeof(WORD));
LZHENV->rson = (WORD *)malloc((N + 257) * sizeof(WORD));
LZHENV->dad = (WORD *)malloc((N + 1) * sizeof(WORD));
LZHENV->text_buf = (UBYTE *)malloc(text_buf_len);
if(!LZHENV->lson || !LZHENV->rson || !LZHENV->dad || !LZHENV->text_buf)
{
StopHuff(LZHENV);
return(NULL);
}
memset(LZHENV->lson,0,(N + 1) * sizeof(WORD));
memset(LZHENV->rson,0,(N + 257) * sizeof(WORD));
memset(LZHENV->dad,0,(N + 1) * sizeof(WORD));
memset(LZHENV->text_buf,' ',(N - F));
LZHENV->InpMax = LZHENV->InpPos = (WORD)sizeof(LZHENV->InpBuf);
LZHENV->OutMax = (WORD)sizeof(LZHENV->OutBuf);
initCRC(LZHENV->crctab);
LZHENV->getbuf = LZHENV->getlen = 0;
LZHENV->match_position = LZHENV->match_length = 0;
for(i = 0; i < N_CHAR; i++)
{
LZHENV->freq[i] = 1;
LZHENV->son[i] = (WORD)(i + T);
LZHENV->prnt[i + T] = (WORD)i;
}
i = 0;
j = N_CHAR;
while(j <= R)
{
LZHENV->freq[j] = (UWORD)(LZHENV->freq[i] + LZHENV->freq[i + 1]);
LZHENV->son[j] = i;
LZHENV->prnt[i] = LZHENV->prnt[i + 1] = j;
i += 2;
j++;
}
LZHENV->freq[T] = 0xffff;
LZHENV->prnt[R] = 0;
return(LZHENV);
}
STATIC VOID reconst(struct lzh_env *LZHENV) /* reconstruction of tree */
{
UWORD f,l;
WORD i,k,j;
/* collect leaf nodes in the first half of the table */
/* and replace the freq by (freq + 1) / 2. */
for(i = k = 0; i < T; ++i)
{
if(LZHENV->son[i] >= T)
{
LZHENV->freq[k] = (UWORD)((LZHENV->freq[i] + 1) / 2);
LZHENV->son[k] = LZHENV->son[i];
k++;
}
}
/* begin constructing tree by connecting sons */
for(i = 0,j = N_CHAR; j < T; i += 2,j++)
{
k = (WORD)(i + 1);
f = LZHENV->freq[j] = (UWORD)(LZHENV->freq[i] + LZHENV->freq[k]);
for(k = (WORD)(j - 1); f < LZHENV->freq[k]; k--);
k++;
l = (UWORD)((j - k) * 2);
memmove(&LZHENV->freq[k + 1],&LZHENV->freq[k],l);
LZHENV->freq[k] = f;
memmove(&LZHENV->son[k + 1],&LZHENV->son[k],l);
LZHENV->son[k] = i;
}
/* connect prnt */
for(i = 0; i < T; i++)
{
if((k = LZHENV->son[i]) >= T)
LZHENV->prnt[k] = i;
else
LZHENV->prnt[k] = LZHENV->prnt[k + 1] = i;
}
}
/* increment frequency of given code by one,and update tree */
STATIC VOID update(struct lzh_env *LZHENV,WORD c)
{
WORD i,j,k,l;
if(LZHENV->freq[R] == MAX_FREQ)
reconst(LZHENV);
c = LZHENV->prnt[c + T];
do
{
k = (WORD)(++LZHENV->freq[c]);
/* if the order is disturbed,exchange nodes */
if(k > LZHENV->freq[l = (WORD)(c + 1)])
{
while(k > LZHENV->freq[++l]);
l--;
LZHENV->freq[c] = LZHENV->freq[l];
LZHENV->freq[l] = k;
i = LZHENV->son[c];
LZHENV->prnt[i] = l;
if(i < T)
LZHENV->prnt[i + 1] = l;
j = LZHENV->son[l];
LZHENV->son[l] = i;
LZHENV->prnt[j] = c;
if(j < T)
LZHENV->prnt[j + 1] = c;
LZHENV->son[c] = j;
c = l;
}
}
while((c = LZHENV->prnt[c]) != 0); /* repeat up to root */
}
STATIC WORD DecodeChar(struct lzh_env *LZHENV)
{
UWORD c;
c = LZHENV->son[R];
/* travel from root to leaf,*/
/* choosing the smaller child node (son[]) if the read bit is 0,*/
/* the bigger (son[]+1) if 1 */
while(c < T)
{
c += GetBit(LZHENV);
c = LZHENV->son[c];
}
c -= T;
update(LZHENV,c);
return((WORD)c);
}
STATIC WORD DecodePosition(struct lzh_env *LZHENV)
{
/* table for decoding the upper 6 bits of position */
STATIC UBYTE d_code[256] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,
0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,
0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,
0x0C,0x0C,0x0C,0x0C,0x0D,0x0D,0x0D,0x0D,
0x0E,0x0E,0x0E,0x0E,0x0F,0x0F,0x0F,0x0F,
0x10,0x10,0x10,0x10,0x11,0x11,0x11,0x11,
0x12,0x12,0x12,0x12,0x13,0x13,0x13,0x13,
0x14,0x14,0x14,0x14,0x15,0x15,0x15,0x15,
0x16,0x16,0x16,0x16,0x17,0x17,0x17,0x17,
0x18,0x18,0x19,0x19,0x1A,0x1A,0x1B,0x1B,
0x1C,0x1C,0x1D,0x1D,0x1E,0x1E,0x1F,0x1F,
0x20,0x20,0x21,0x21,0x22,0x22,0x23,0x23,
0x24,0x24,0x25,0x25,0x26,0x26,0x27,0x27,
0x28,0x28,0x29,0x29,0x2A,0x2A,0x2B,0x2B,
0x2C,0x2C,0x2D,0x2D,0x2E,0x2E,0x2F,0x2F,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F
};
STATIC UBYTE d_len[256] =
{
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
};
UWORD i,j,c;
/* recover upper 6 bits from table */
i = GetByte(LZHENV);
c = (UWORD)(d_code[i] << 6);
j = d_len[i];
/* read lower 6 bits verbatim */
j -= 2;
while(j--)
i = (UWORD)((i << 1) + GetBit(LZHENV));
return((WORD)(c | (i & 0x3f)));
}
// LZH decompression
int BTXService::LZH_Decode(FILE *fi,FILE *fo,long filesize,ULONG *CRC_32)
{
ULONG OUTCRC = 0xffffffff,*crctab;
struct lzh_env *LZHENV;
WORD i,j,k,r,c;
ULONG count;
if(!(LZHENV = StartHuff()))
return(-1);
LZHENV->infile = fi;
LZHENV->outfile = fo;
r = N - F;
crctab = LZHENV->crctab;
for(count = 0; count < filesize; )
{
if((c = DecodeChar(LZHENV)) < 256)
{
if(! OutByt(LZHENV,c))
{
StopHuff(LZHENV);
return(-1);
}
OUTCRC = FCS_32(OUTCRC,c);
LZHENV->text_buf[r++] = (UBYTE) c;
r &= (N - 1);
count++;
}
else
{
i = (WORD)((r - DecodePosition(LZHENV) - 1) & (N - 1));
j = (WORD)(c - 255 + THRESHOLD);
for(k = 0; k < j; ++k)
{
c = LZHENV->text_buf[(i + k) & (N - 1)];
if(!OutByt(LZHENV,c))
{
StopHuff(LZHENV);
return(-1);
}
OUTCRC = FCS_32(OUTCRC,c);
LZHENV->text_buf[r++] = (UBYTE) c;
r &= (N - 1);
count++;
}
}
}
if(LZHENV->OutPos)
fwrite(LZHENV->OutBuf,LZHENV->OutPos,1,LZHENV->outfile);
StopHuff(LZHENV);
*CRC_32 = OUTCRC;
return(0);
}
/****************************************************************************/
// Run length decompression
int BTXService::RLE_Decode(FILE *in,FILE *out,long filesize,ULONG *CRC_32)
{
enum { STATE_Raw,STATE_Repeat };
ULONG *crctab;
if(crctab = (ULONG *)malloc(sizeof(ULONG) * 256))
{
ULONG crc = ~0;
long total = 0;
int c,lastc = 0,x,n,i;
int state = STATE_Raw;
int result = 0;
BOOL eaten;
initCRC(crctab);
while(total < filesize && !result)
{
if((c = fgetc(in)) == EOF)
{
result = -1;
break;
}
eaten = FALSE;
switch(state)
{
case STATE_Raw:
// Start a repeat run?
if(c == 0x12)
{
x = lastc;
eaten = TRUE;
state = STATE_Repeat;
}
break;
case STATE_Repeat:
// Two 0x12 bytes in a row, cancel repeat
// and just send the second 0x12
if(c == 0x12)
state = STATE_Raw;
else
{
n = c - 0x20 - 1; // first char always gets written
eaten = TRUE;
state = STATE_Raw;
for(i = 0 ; !result && total < filesize && i < n ; i++)
{
if(fputc(x,out) == EOF)
result = -1;
else
{
crc = FCS_32(crc,x);
total++;
}
}
}
break;
}
if(!eaten)
{
if(fputc(c,out) == EOF)
result = -1;
else
{
crc = FCS_32(crc,c);
total++;
}
}
lastc = c;
}
free(crctab);
*CRC_32 = crc;
return(result);
}
else
return(-1);
}